﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using EntGuayasSLA.BL.Archivos.Io;

namespace EntGuayasSLA.BL.Archivos.Pdf
{
    public static class EnvelopedCms
    {
        public static void EncryptP7M(string sourceDocument, X509Certificate2 signatureCert)
        {
            byte[] bytes_in = System.IO.File.ReadAllBytes(sourceDocument);
            byte[] bytes = EncryptMsg(bytes_in, signatureCert);
            FileIO.ByteArrayToFile(sourceDocument + ".p7m", bytes);

        }

        public static void DencryptP7M(string sourceDocument,string outDocumentm, X509Certificate2 signatureCert)
        {
            string fileExt = sourceDocument.Substring(sourceDocument.LastIndexOf('.') + 1);

            if (fileExt.ToLower() == "p7m")
            {
                  //  Convert message to array of bytes for signing.
                  byte[] bytes = System.IO.File.ReadAllBytes(sourceDocument);
                  //  Prepare object in which to decode and decrypt.
                  System.Security.Cryptography.Pkcs.EnvelopedCms envelopedCms = new System.Security.Cryptography.Pkcs.EnvelopedCms();
                  //  Decode the message.
                  envelopedCms.Decode(bytes);
                  //  Decode the message.
                  //envelopedCms.Decrypt(envelopedCms.RecipientInfos[0]);
                  //Create a collection and add two of the certificates.
                  X509Certificate2Collection collection = new X509Certificate2Collection();
                  collection.Add(signatureCert);
                  envelopedCms.Decrypt(collection);
                  //  The decrypted message occupies the ContentInfo property
                  //  after the Decrypt method is invoked.
                  byte[] outbytes = envelopedCms.ContentInfo.Content;
                  FileIO.ByteArrayToFile(outDocumentm, outbytes);
        

         }
         else
         {
            throw  new Exception("Formato incorrecto");          
         }
        
        }

        //  Encrypt the message with the public key of
        //  the recipient. This is done by enveloping the message by
        //  using an EnvelopedCms object.
        static private byte[] EncryptMsg(
            Byte[] msg,
            X509Certificate2 recipientCert)
        {
            //  Place the message in a ContentInfo object.
            //  This is required to build an EnvelopedCms object.
            ContentInfo contentInfo = new ContentInfo(msg);

            //  Instantiate an EnvelopedCms object with the ContentInfo
            //  above.
            //  Has default SubjectIdentifierType IssuerAndSerialNumber.
            //  Has default ContentEncryptionAlgorithm property value
            //  RSA_DES_EDE3_CBC.
            System.Security.Cryptography.Pkcs.EnvelopedCms envelopedCms = new System.Security.Cryptography.Pkcs.EnvelopedCms(contentInfo);

            //  Formulate a CmsRecipient object that
            //  represents information about the recipient 
            //  to encrypt the message for.
            CmsRecipient recip1 = new CmsRecipient(
                SubjectIdentifierType.IssuerAndSerialNumber,
                recipientCert);


            //Console.Write(
            //    "Encrypting data for a single recipient of " +
            //    "subject name {0} ... ",
            //    recip1.Certificate.SubjectName.Name);
            //  Encrypt the message for the recipient.
            envelopedCms.Encrypt(recip1);
            //Console.WriteLine("Done.");

            //  The encoded EnvelopedCms message contains the message
            //  ciphertext and the information about each recipient 
            //  that the message was enveloped for.
            return envelopedCms.Encode();
        }

        //  Decrypt the encoded EnvelopedCms message.
        static private Byte[] DecryptMsg(byte[] encodedEnvelopedCms)
        {
            //  Prepare object in which to decode and decrypt.
            System.Security.Cryptography.Pkcs.EnvelopedCms envelopedCms = new System.Security.Cryptography.Pkcs.EnvelopedCms();

            //  Decode the message.
            envelopedCms.Decode(encodedEnvelopedCms);

            //  Display the number of recipients the message is
            //  enveloped for; it should be 1 for this example.
            //DisplayEnvelopedCms(envelopedCms, false);

            //  Decrypt the message for the single recipient.
            //Console.Write("Decrypting Data ... ");
            envelopedCms.Decrypt(envelopedCms.RecipientInfos[0]);
            //Console.WriteLine("Done.");

            //  The decrypted message occupies the ContentInfo property
            //  after the Decrypt method is invoked.
            return envelopedCms.ContentInfo.Content;
        }

        //  Display the ContentInfo property of an EnvelopedCms object.
        static private void DisplayEnvelopedCmsContent(String desc,
            System.Security.Cryptography.Pkcs.EnvelopedCms envelopedCms)
        {
            Console.WriteLine(desc + " (length {0}):  ",
                envelopedCms.ContentInfo.Content.Length);
            foreach (byte b in envelopedCms.ContentInfo.Content)
            {
                Console.Write(b.ToString() + " ");
            }
            Console.WriteLine();
        }

        //  Display some properties of an EnvelopedCms object.
        static private void DisplayEnvelopedCms(System.Security.Cryptography.Pkcs.EnvelopedCms e,
            Boolean displayContent)
        {
            Console.WriteLine("\nEnveloped CMS/PKCS #7 Message " +
                "Information:");
            Console.WriteLine(
                "\tThe number of recipients for the Enveloped CMS/PKCS " +
                "#7 is: {0}", e.RecipientInfos.Count);
            for (int i = 0; i < e.RecipientInfos.Count; i++)
            {
                Console.WriteLine(
                    "\tRecipient #{0} has type {1}.",
                    i + 1,
                    e.RecipientInfos[i].RecipientIdentifier.Type);
            }
            if (displayContent)
            {
                DisplayEnvelopedCmsContent("Enveloped CMS/PKCS " +
                    "#7 Content", e);
            }
            Console.WriteLine();
        }

        /// <summary>
        /// Comprobación y eliminación de una firma
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        static byte[] VerifyAndRemoveSignature(byte[] data)
        {
            // create SignedCms
            SignedCms signedMessage = new SignedCms();

            // deserialize PKCS #7 byte array
            signedMessage.Decode(data);

            // check signature
            // false checks signature and certificate
            // true only checks signature
            signedMessage.CheckSignature(false);

            // access signature certificates (if needed)
            foreach (SignerInfo signer in signedMessage.SignerInfos)
            {
                Console.WriteLine("Subject: {0}",
                  signer.Certificate.Subject);
            }

            // return plain data without signature
            return signedMessage.ContentInfo.Content;
        }


    }
}